package com.yanqu.road.server.manger;

import com.yanqu.road.entity.enums.eMonopolyMarketResType;
import com.yanqu.road.entity.monopolymarket.group.IMonopolyMarketGroup;
import com.yanqu.road.entity.monopolymarket.office.MonopolyMarketOfficeSeatConfig;
import com.yanqu.road.entity.monopolymarket.resgrab.MonopolyMarketResGrabPointValue;
import com.yanqu.road.entity.systemgroup.newmonopolymarket.config.NewMonopolyMarketResConfigData;
import com.yanqu.road.entity.systemgroup.newmonopolymarket.resgrab.NewMonopolyMarketResGrabMap;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.util.*;


public class NewMonopolyMarketCommonMgr {

    private static final Logger logger = LogManager.getLogger(NewMonopolyMarketCommonMgr.class.getName());

    /**
     * 榷场系统位
     */
    public static final int SYSTEM_BIT = 0b1111;

    /**
     * 榷署每个等级官员 每行数量
     */
    public static final String MONOPOLYMARKET_LEVEL_NUM = "1;1|2;2|3;2|4;3|5;3|6;3|7;3|8;3|9;3";

    /**
     * 榷署每个等级官员 每行数量
     */
    public static Map<Integer,Integer> perLineNumMap = new HashMap<>();

    static {
        String[] levelNumStr = MONOPOLYMARKET_LEVEL_NUM.split("\\|");
        for (String item : levelNumStr){
            if(item.contains(";")){
                String[] levelNum = item.split(";");
                int level = Integer.valueOf(levelNum[0]);
                int num = Integer.valueOf(levelNum[1]);
                perLineNumMap.put(level, num);
            }
        }
    }

    /**
     * 计算榷署位置的等级
     */
    public static int calOfficePosLevel(List<MonopolyMarketOfficeSeatConfig> seatConfigList, int posIndex){
        int level = 0;
        for(MonopolyMarketOfficeSeatConfig item : seatConfigList){
            if(posIndex >= item.startIndex && posIndex <= item.endIndex){
                return item.getLevel();
            }
        }
        return level;
    }

    /**
     * 计算榷署每隔等级 起 始位置
     * @param serverNum 区服數量
     * @param resConfigList 等级
     * @return
     */
    public static List<MonopolyMarketOfficeSeatConfig> calNewMonopolyMarketOfficeSeatConfigList(int serverNum, int userNum, List<NewMonopolyMarketResConfigData> resConfigList){
        List<MonopolyMarketOfficeSeatConfig> list = new ArrayList<>();
        int startIndex = 0;

        List<String> queShuList = StringUtils.stringToStringList(GameConfig.NEWMONOPOLYMARKET_QUESHU_PARAM, "\\|");
        int lv = 1;
        for (String levelParam : queShuList) {
            List<Integer> paramList = StringUtils.stringToIntegerList(levelParam, ";");
            int num;
            int min = paramList.get(0) * perLineNumMap.get(lv);
            int max = paramList.get(1);
            int len = BigDecimal.valueOf(userNum * paramList.get(2)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue();
            if(max == -1){
                num = Math.max(min, len);
            }else {
                max = max * perLineNumMap.get(lv);
                if(len > max){
                    num = max;
                }else {
                    num = len;
                }
                num = Math.max(num, min);
            }
            int endIndex = startIndex + num - 1;
            list.add(new MonopolyMarketOfficeSeatConfig(lv, startIndex, endIndex));
            lv++;
            startIndex = endIndex + 1;
        }
        return list;
    }

    /**
     * 计算产出速度
     *
     * @param serverNum 暂时无用，写死千分比
     * @param reward
     * @param rewardAdd
     * @param id
     * @param no
     * @return
     */
    public static int calResRate(int serverNum, int reward, int rewardAdd, int id, int no) {
        long coefficient = 1000;
        no = Math.max(no, 1);
        if(no > 1){
            List<Integer> posNumList = StringUtils.stringToIntegerList("1,7,13,20,39,59,79,95,125", ",");
            int idx = id % 10;
            if(idx > posNumList.size()){
                idx = posNumList.size();
            }
            if(idx == 0){
                idx = 1;
            }
            no = Math.min(no, posNumList.get(idx - 1));
        }
        int rate = (int) ((reward * coefficient - (no - 1) * rewardAdd + 1000 - 1) / 1000);
        return rate;
    }

    /**
     * 初始化地图  左上角为（0,0） index = 0     01234----->
     *                                         1
     *                                         2
     *                                         3
     * @param type 资源类型
     * @param pointNum 实际据点数量
     * @param group 分组
     * @param configList 资源等级配置
     * @param pointLvNumMap
     */
    public static NewMonopolyMarketResGrabMap initResGrabMap(int type, int pointNum, IMonopolyMarketGroup group, List<NewMonopolyMarketResConfigData> configList, Map<Integer, Integer> pointLvNumMap, boolean isShowLog){
        logger.info("开始初始化榷场地图。groupId :{},type:{},changTime:{}", group.getMonopolyMarketGroupId(), type, group.getMonopolyMarketChangeTime());
        Random random = new Random(group.getMonopolyMarketChangeTime() + group.getMonopolyMarketGroupId() + type);
        // 地图边长
        int side = (int)Math.ceil(Math.pow(pointNum * ConfigMgr.getNewMonopolyMapSize() / 1000, 0.5));
        // 最大长度
        double maxLength = Math.pow(0.5, 0.5) * side;
        // 格子总数
        int totalNum = side * side;
        List<MonopolyMarketResGrabPointValue> pointList = new ArrayList<>(totalNum);
        // 循环次数
        for (int j = 0; j < totalNum; j++) {
            // 据点到中心点的长度
            int x = j % side;
            int y = j / side;
            double xy = Math.sqrt(Math.pow(x - side/2,2) + Math.pow(y - side/2,2));
            double value = (1 - xy / maxLength) * ConfigMgr.getNewMonopolyMapMidValue();
            MonopolyMarketResGrabPointValue pointValue = new MonopolyMarketResGrabPointValue();
            pointValue.value = value;
            pointValue.index = j;
            pointList.add(pointValue);
        }
        for (int i = 1; i <= ConfigMgr.getNewMonopolyMapRound(); i++) {
            int m = ConfigMgr.getNewMonopolyMapBase() + (i - 1) * ConfigMgr.getNewMonopolyMapAdd();
            int turns = (int)Math.ceil(side / 2);
            for (int j = 0; j < turns; j++) {
                int length = side - j * 2 -1;
                // 起点
                // 左到右
                for (int k = 0; k < length; k++) {
                    int x = j + k;
                    int y = j;
                    checkPoint(random,x,y,side,m,pointList);
                }
                // 右上到右下
                for (int k = 0; k < length; k++) {
                    int x = side - 1 - j;
                    int y = k + j;
                    checkPoint(random,x,y,side,m,pointList);
                }
                // 右下到左下
                for (int k = 0; k < length; k++) {
                    int x = side - 1 - j - k;
                    int y = side - 1 - j;
                    checkPoint(random,x,y,side,m,pointList);
                }
                // 左下到上
                for (int k = 0; k < length; k++) {
                    int x = j;
                    int y = side - 1 - j - k;
                    checkPoint(random,x,y,side,m,pointList);
                }
            }
        }
        pointList.sort((t1,t2)->{
            return Double.compare(t2.value,t1.value);
        });
        NewMonopolyMarketResGrabMap map = new NewMonopolyMarketResGrabMap();
        map.type = type;
        map.side = side;
        map.pointNum = totalNum;
        // 所有的据点index
        List<Integer> allIndexList = new ArrayList<>();
        for (int i = configList.size() - 1; i >= 0; i--) {
            NewMonopolyMarketResConfigData item = configList.get(i);
            int num = pointLvNumMap.getOrDefault(item.getLevel(), 0);
            if(num == 0){
                continue;
            }
            List<Integer> list = map.levelIndexListMap.get(item.getLevel());
            if(list == null){
                list = new ArrayList<>();
                map.levelIndexListMap.put(item.getLevel(),list);
            }
            for (int j = 0; j < num; j++) {
                MonopolyMarketResGrabPointValue pointValue = pointList.remove(0);
                map.indexLevelMap.put(pointValue.index, item.getLevel());
                list.add(pointValue.index);
            }
            list.sort((t1,t2)->{ return Integer.compare(t1,t2); });
            allIndexList.addAll(list);
        }
        map.levelIndexListMap.put(0,allIndexList);

        map.indexLevelList = new ArrayList<>(totalNum);
        int index = 0;
        for (int i = 0; i < side; i++) {
            for (int j = 0; j < side; j++) {
                Integer level = map.indexLevelMap.getOrDefault(index++, 0);
                map.indexLevelList.add(level);
                if(level > 0){
                    map.realNum++;
                }
            }
        }
        if(isShowLog){
            // 打印地图
            int tempSide = side;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < map.indexLevelList.size(); i++) {
                int level = map.indexLevelList.get(i);
                if(level == 0){
                    sb.append("* ");
                }else {
                    sb.append(level+" ");
                }
                if(--tempSide == 0){
                    logger.info(sb);
                    tempSide = side;
                    sb.setLength(0);
                }
            }
        }
        logger.info("初始化榷场地图结束。groupId:{}, 地图边长：{},最大长度：{},实际可开采格子：{}",group.getMonopolyMarketGroupId(),side,maxLength,pointNum);
        return map;
    }

    /**
     * 检查格子
     * 格子判断如下：
     * 	计算格子周围九宫格包括自己的总数值为n
     * 	随机一个数r=random(0,1)
     * 	若r<n/m 则该格子数值+1，否则数值不变
     * @param random
     * @param x
     * @param y
     * @param side
     * @param m
     * @param pointList
     */
    private static void checkPoint(Random random ,int x, int y, int side,int m, List<MonopolyMarketResGrabPointValue> pointList){
//        logger.info("x:{}，y:{}",x, y );
        double n = calJiuGongGeValue(x, y ,side,pointList);
        double r = random.nextDouble();
        if(r < n / m){
            int index = calIndex(x,y,side);
            MonopolyMarketResGrabPointValue item = pointList.get(index);
            item.value = item.value + 1;
        }
    }

    /**
     * 计算周围九宫格的值
     * @return
     */
    private static double calJiuGongGeValue(int x,int y ,int side, List<MonopolyMarketResGrabPointValue> pointValueList){
        // 寻找九宫格的中心点
        int centerX = x;
        int centerY = y;
        if(centerX == 0 ){
            // 右移
            centerX += 1;
        }else if (centerX == side - 1){
            centerX -= 1;
        }
        if(centerY == 0 ){
            // 右移
            centerY += 1;
        }else if(centerY == side - 1){
            centerY -= 1;
        }
        Set<Integer> set = getAroundPoints(centerX, centerY,side,1);
        int index = calIndex(centerX, centerY,side);
        set.add(index);
        double totalValues = 0;
        for (Integer i : set){
            totalValues += pointValueList.get(i).value;
        }
//        logger.info("index : {},的九宫格为:{}",calIndex(x,y,side), set);
        return totalValues;
    }

    /**
     * 获得 中心点 周围 据点集合
     * @param x
     * @param y
     * @param side 地图边长
     * @param r 第几圈
     * @return
     */
    private static Set<Integer> getAroundPoints(int x,int y,int side,int r){
        Set<Integer> set = new HashSet<>();
        // 上
        int upX = x;
        int upY = y - r;
        set.addAll(getXPoints(upX,upY,side,r));
        // 下
        int downX = x;
        int downY = y + r;
        set.addAll(getXPoints(downX,downY,side,r));
        // 左
        int leftX = x - r;
        int leftY = y;
        set.addAll(getYPonits(leftX,leftY,side,r));
        // 右
        int rightX = x + r;
        int rightY = y;
        set.addAll(getYPonits(rightX,rightY,side,r));
        return set;
    }

    /**
     * 获得 在x轴上距离该点 小于等于r 的集合
     * @param x
     * @param y
     * @param side
     * @param r
     * @return
     */
    private static Set<Integer> getXPoints(int x,int y,int side,int r){
        Set<Integer> set = new HashSet<>();
        getValue(x, y,side,set);
        for (int i = 1; i <= r; i++) {
            getValue(x - i,y,side,set);
            getValue(x + i,y,side,set);
        }
        return set;
    }

    /**
     * 获得 在y轴上距离该点 小于等于r 的集合
     * @param x
     * @param y
     * @param side
     * @param r
     * @return
     */
    private static Set<Integer> getYPonits(int x, int y, int side, int r){
        Set<Integer> set = new HashSet<>();
        getValue(x, y,side,set);
        for (int i = 1; i <= r; i++) {
            getValue(x,y - i,side,set);
            getValue(x,y + i,side,set);
        }
        return set;
    }

    private static Integer getValue(int x,int y,int side,Set<Integer> set){
        if(x < 0 || x > side -1){
            return null;
        }
        if(y < 0 || y > side -1){
            return null;
        }
        int index = calIndex(x,y,side);
        set.add(index);
        return index;
    }

    /**
     * 计算点对应的 索引位置
     * @param x
     * @param y
     * @param side
     * @return
     */
    public static int calIndex(int x, int y ,int side){
        return x + y * side;
    }

    /**
     * 获取榷场 资源站产出道具id
     * @param type
     * @return
     */
    public static int getGoodsId(int type){
        int goodsId = 0;
        if(type == eMonopolyMarketResType.RES_KING_NEW.getValue()){
            goodsId = GameConfig.NEWMONOPOLYMARKET_BAIYE_ID;
        }else if(type == eMonopolyMarketResType.RES_QUEEN_NEW.getValue()){
            goodsId = GameConfig.NEWMONOPOLYMARKET_CAIYI_ID;
        }
        return goodsId;
    }

    /**
     * 榷场系统是否开启中（仅玩家触发，不能用于定时器逻辑）
     * @param type
     * @return
     */
    public static boolean isSystemOpenTime(int type){
        int now = DateHelper.getCurrentSecond();
        long weekStartTime = DateHelper.getThisWeekStartTime(GameConfig.DAY_SYSTEM_RESET_TIME) / 1000;
        weekStartTime = weekStartTime - (GameConfig.DAY_SYSTEM_RESET_TIME - 1) * DateHelper.DAY_SECONDS;
        if(type == eMonopolyMarketResType.OFFICE_NEW.getValue()){
            //榷署没有休息期
            if(ConfigMgr.getOfficeOpenSecondNew() + weekStartTime <= now && now < ConfigMgr.getOfficeEndSecondNew() + weekStartTime){
                return true;
            }
        }else if(type == eMonopolyMarketResType.RES_KING_NEW.getValue()){
            if(ConfigMgr.getResGrabKingOpenSecondNew() + weekStartTime <= now && now < ConfigMgr.getResGrabKingEndSecondNew() + weekStartTime){
                // 判断开启
                int todayZeroTime = DateHelper.getTodayZeroTime();
                // 每日的休息期
                if(ConfigMgr.getKingDailyOpenTimeNew() + todayZeroTime <= now && now < ConfigMgr.getKingDailyEndTimeNew() + todayZeroTime){
                    return true;
                }
            }
        }else if(type == eMonopolyMarketResType.RES_QUEEN_NEW.getValue()){
            // 判断开启
            if(ConfigMgr.getResGrabQueenOpenSecondNew() + weekStartTime <= now && now < ConfigMgr.getResGrabQueenEndSecondNew() + weekStartTime){
                int todayZeroTime = DateHelper.getTodayZeroTime();
                // 每日的休息期
                if(ConfigMgr.getQueenDailyOpenTimeNew() + todayZeroTime <= now && now < ConfigMgr.getQueenDailyEndTimeNew() + todayZeroTime){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 每周结算时间（周日的22点）
     * @param anyTimeInWeek
     */
    public static boolean inWeekSettlementTime(int anyTimeInWeek, int now){
        long weekStartTime = DateHelper.getThisWeekStartTime(anyTimeInWeek, GameConfig.DAY_SYSTEM_RESET_TIME) / 1000;
        weekStartTime = weekStartTime - (GameConfig.DAY_SYSTEM_RESET_TIME - 1) * DateHelper.DAY_SECONDS;
        return now > ConfigMgr.getNewMonopolyOpenRankTime() + weekStartTime;
    }

    /**
     * 每周领奖时间（周日22：05 - 周一 23点59分59秒）
     */
    public static boolean inWeekRewardTime(int anyTimeInWeek, int now){
        long weekStartTime = DateHelper.getThisWeekStartTime(anyTimeInWeek, GameConfig.DAY_SYSTEM_RESET_TIME) / 1000;
        weekStartTime = weekStartTime - (GameConfig.DAY_SYSTEM_RESET_TIME - 1) * DateHelper.DAY_SECONDS;
        return now >  ConfigMgr.getNewMonopolyOpenRankTime() + weekStartTime + 5 * DateHelper.MINUTE_SECONDS
                && now < ConfigMgr.getNewMonopolyEndRankTime() + weekStartTime;
    }

    /**
     * 获取 该时间 的榷署结束时间
     * @param time 要计算的时间
     * @param weekEndTime  周结束的时间
     * @return
     */
    public static int getResetOfficeTime(int time, int weekEndTime){
        int weekStartTime = time - (GameConfig.DAY_SYSTEM_RESET_TIME - 1) * (int)DateHelper.DAY_SECONDS;
        return DateHelper.getWeekBeginTimestamp(weekStartTime) + weekEndTime;
    }

    public static int getResGrabPointCD(int type){
        int cd = 0;
        if(type == eMonopolyMarketResType.RES_KING_NEW.getValue()){
            cd = GameConfig.NEWMONOPOLYMARKET_REWARD_CD_2;
        }else if(type == eMonopolyMarketResType.RES_QUEEN_NEW.getValue()){
            cd = GameConfig.NEWMONOPOLYMARKET_REWARD_CD_3;
        }
        return cd;
    }

}
